import json

import matplotlib as mpl
from flask import request

from app.Package.pyChemometrics.ChemometricsOrthogonalPLSDA import ChemometricsOrthogonalPLSDA
from app.Controllers.BaseController import BaseController
from ...Package.entity.PLSDARequestBody import PLSDARequestBody

mpl.use('Agg')
import matplotlib.pyplot as plt

from .CommonService import readData, getSavePath, getWebPath, getImagePath, getWebImagePath, getProjectInfo, \
    readDataForPLSDA, readDataForPLSR
from app.Package.pyChemometrics.ChemometricsPLSDA import ChemometricsPLSDA
from app.Package.pyChemometrics.ChemometricsScaler import ChemometricsScaler

import numpy as np

# 解析PLSDA的请求表单
def unpackPLSDARequestBody(input_data):
    xfile = input_data.xfile
    yfile = input_data.yfile
    ppmfile = input_data.ppmfile
    ncomps = input_data.ncomps
    scaling_type = input_data.scaling_type
    ycol = input_data.ycol
    thread_path = input_data.thread_path
    return xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path

# 构建一个PLSDA模型
def getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, t1, t2, outliers_index=None):
    x, y, ppm = readDataForPLSDA(xfile, yfile, ppmfile, ycol, t1, t2, outliers_index)
    yn = y[:, ycol]
    PLSDA_model = ChemometricsPLSDA(n_components=ncomps, x_scaler=ChemometricsScaler(scale_power=scaling_type))
    PLSDA_model.fit(x, yn)
    return PLSDA_model, x, y, ppm, yn

# 构建一个PLSR模型
def getPLSRModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, outliers_index=None):
    x, y, ppm = readDataForPLSR(xfile, yfile, ppmfile, ycol, outliers_index)
    yn = y[:, ycol]
    PLSDA_model = ChemometricsPLSDA(n_components=ncomps, x_scaler=ChemometricsScaler(scale_power=scaling_type))
    PLSDA_model.fit(x, yn)
    return PLSDA_model, x, y, ppm, yn


# 构建一个OrthogonalPLSDA模型
def getOrthogonalPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, t1, t2, outliers_index=None):
    x, y, ppm = readDataForPLSDA(xfile, yfile, ppmfile, ycol, t1, t2, outliers_index)
    yn = y[:, ycol]
    PLSDA_model = ChemometricsOrthogonalPLSDA(ncomps=ncomps, xscaler=ChemometricsScaler(scale_power=scaling_type))
    PLSDA_model.fit(x, yn)
    return PLSDA_model, x, y, ppm, yn

# 将表单信息封装进类中
def PLSDACommonProcess():
    userId, projectId, data, label, coordinate, savePath = getProjectInfo()
    formdata = request.data.decode('utf-8')
    formjson = json.loads(formdata)
    PLSDA = PLSDARequestBody(data, label, coordinate, savePath)
    PLSDA.set_data(formjson)
    return PLSDA

# Score画图
def getPLSDAScorePlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    if input_data.discrete_color_col_num is not None:
        discrete_color = y[:, input_data.discrete_color_col_num]
    else:
        discrete_color = None
    fig, ax = PLSDA_model.plot_scores(comps=input_data.score_plot_comps, plot_title=input_data.plot_title,
                                      color=discrete_color, discrete=input_data.discrete,
                                      label_outliers=input_data.label_outliers)
    imageFilename = "PLSDAScore"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 获取PLSDAScree的画图
def getPLSDAScreePlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    plateau, fig, ax = PLSDA_model.scree_plot(x, yn, total_comps=input_data.scree_total_comps)
    imageFilename = "PLSDAScree"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据表单输入的信息构造PLSDA模型后，找出样本中的离群点，并返回离群点，但是返回的是删除后的索引
# 仍需要修改
def getPLSDAOutlier(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    outlier_idx = PLSDA_model.outlier(x, measure=input_data.outlier_measure, alpha=input_data.outlier_alpha)
    resultData = {"outlierIndex": outlier_idx.tolist()}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据表单输入的信息构造PLSDA模型后，进行CvPlot操作，并返回生成的图片的url
def getPLSDACvPlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    q2y, q2x, fig, ax = PLSDA_model.repeated_cv(x, yn, total_comps=input_data.cv_total_comps, repeats=input_data.cv_repeats)
    imageFilename = "PLSDACv"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据表单输入的信息构造PLSDA模型后，进行CvROCPlot操作，并返回生成的图片的url
def getPLSDACvROCPlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    PLSDA_model.cross_validation(x, yn)
    PLSDA_model.plot_cv_ROC()
    imageFilename = "PLSDACvROC"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据表单输入的信息构造PLSDA模型后，进行PermutationTest
# 仍然需要修改
def getPLSDAPermutationTest(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    permt = PLSDA_model.permutation_test(x, yn, input_data.permutation_test_epochs)
    Filename = "permutations_plsda.npy"
    Path = getSavePath(thread_path) + Filename
    np.save(Path, permt)
    webPath = getWebPath(thread_path) + Filename
    resultData = {"webPath": webPath, "permutation_test_npy": "permutations_plsda.npy"}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据PermutationTest得到的结果进行画图
# 画图细节需要进行完善
def getPLSDAPermutationTestPlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    if input_data.permutation_test_npy is not None:
        permt = np.load(thread_path + input_data.permutation_test_npy, allow_pickle=True)
    else:
        return BaseController().error(msg="尚未进行测试")
    fig, ax = PLSDA_model.plot_permutation_test(permt, metric=input_data.permutation_test_metric)
    plt.xlabel(str(input_data.permutation_test_metric))
    plt.ylabel('Counts')
    imageFilename = "PLSDAPermutationTest"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据表单输入的信息构造PLSDA模型后，进行ModelParametersPlot操作，并返回生成的图片的url
# plottype还没做
def getPLSDAModelParametersPlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    PLSDA_model.cross_validation(x, yn)
    PLSDA_model.plot_model_parameters(input_data.model_parameters, component=input_data.model_comp, sigma=input_data.model_sigma, cross_val=input_data.model_cross_val, xaxis=ppm)
    plt.gca().invert_xaxis()
    imageFilename = "PLSDAModelParameters"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# OrthogonalPLSDAScore的画图
def getOrthogonalPLSDAScorePlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getOrthogonalPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    if input_data.discrete_color_col_num is not None:
        discrete_color = y[:, input_data.discrete_color_col_num]
    else:
        discrete_color = None
    fig, ax = PLSDA_model.plot_scores(orthogonal_component=input_data.orthogonal_component, plot_title=input_data.plot_title,
                                      color=discrete_color, discrete=input_data.discrete,
                                      label_outliers=input_data.label_outliers)
    imageFilename = "OrthogonalPLSDAScore"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 根据表单输入的信息构造OrthogonalPLSDA模型后，进行ModelParametersPlot操作，并返回生成的图片的url
# bar还没做
def getOrthogonalPLSDAModelParametersPlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getOrthogonalPLSDAModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.test_type1, input_data.test_type2, input_data.outliers_index)
    PLSDA_model.cross_validation(x, yn)
    PLSDA_model.plot_model_parameters(input_data.model_parameters, orthogonal_component=input_data.model_comp, sigma=input_data.model_sigma, cross_val=input_data.model_cross_val, xaxis=ppm, bar=False)
    plt.gca().invert_xaxis()
    imageFilename = "OrthogonalPLSDAModelParameters.png"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# PLSRScore画图
def getPLSRScorePlot(input_data):
    xfile, yfile, ppmfile, ncomps, ycol, scaling_type, thread_path = unpackPLSDARequestBody(input_data)
    PLSDA_model, x, y, ppm, yn = getPLSRModel(xfile, yfile, ppmfile, ncomps, ycol, scaling_type, input_data.outliers_index)
    if input_data.discrete_color_col_num is not None:
        discrete_color = y[:, input_data.discrete_color_col_num]
    else:
        discrete_color = None
    fig, ax = PLSDA_model.plot_scores(comps=input_data.score_plot_comps, plot_title=input_data.plot_title,
                                      color=discrete_color, discrete=input_data.discrete,
                                      label_outliers=input_data.label_outliers)
    imageFilename = "PLSRScore"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath":webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)

# 还差permthist
# 还差单变量分析和plsda对比的还没做
